#
# LuckyBot4, a python IRC bot
# (c) Copyright 2008 by Lucas van Dijk
# http://www.return1.net
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
#
# $Id: irc.py 62 2009-03-30 23:42:42Z luckyluke56 $
#

from luckybot.luckynet.protocols import irc
import gobject

class Channel(object):
	"""
		Represents an IRC Channel
	"""

	def __init__(self, channel, protocol):
		self.channel = channel
		self._protocol = protocol

	# Simple wrapper functions
	def send_pm(self, text):
		"""
			Send message to channel
		"""

		self._protocol.send_pm(self.channel, text)

	def send_notice(self, text):
		"""
			Send notice to channel
		"""

		self._protocol.send_notice(self.channel, text)

	def send_action(self, text):
		"""
			Send action to channel like /me
		"""

		self._protocol.send_action(self.channel, text)

	def part(self):
		"""
			Leave this channel
		"""

		self._protocol.part(self.channel)

	def __str__(self):
		return self.channel

class User(object):
	"""
		Represents an user on IRC
	"""

	def __init__(self, message, protocol, bot):
		self._message = message
		self.nick = message.nick
		self.realname = message.realname
		self.hostname = message.hostname

		self._protocol = protocol
		self.bot = bot

	# Simple wrapper functions
	def send_pm(self, text):
		"""
			Send user a private message
		"""

		self._protocol.send_pm(self.nick, text)

	def send_notice(self, text):
		"""
			Send user a notice
		"""

		self._protocol.send_notice(self.nick, text)

	def send_action(self, text):
		"""
			Send the user an action like the /me command
		"""

		self._protocol.send_action(self.nick, text)

	def kick(self, reason = ""):
		"""
			Kick the user from the current channel
		"""

		self._protocol.kick(self._message.channel, self.nick, reason)

	def check_logged_in(self):
		"""
			Check if the user is logged in
		"""

		return self.bot.auth.check_logged_in(self.nick)

	def login(self):
		"""
			Log the user in
		"""

		self.bot.auth.log_in(self.nick)

	def logout(self):
		"""
			Log user out
		"""

		self.bot.auth.log_out(self.nick)

	def __str__(self):
		return self.nick

class Event(gobject.GObject):
	"""
		The main IRC event object. Each command handler of a plugin
		receives this object

		it contains instances of Channel class and User.
	"""

	def __init__(self, message, protocol, bot):
		gobject.GObject.__init__(self)

		if isinstance(message, irc.ChannelMessage):
			self.channel = Channel(message.channel, protocol)
			self.user = User(message, protocol, bot)

		self.client = protocol
		self.message = message
		self.bot = bot


gobject.type_register(Event)

class Client(irc.IRCClient, gobject.GObject):
	"""
		This class handles parsing incoming data
	"""

	__gsignals__ = {
		'irc-event': (gobject.SIGNAL_RUN_LAST, None, (Event,)),
		'data-received': (gobject.SIGNAL_RUN_LAST, None, (str,)),
		'data-sent': (gobject.SIGNAL_RUN_LAST, None, (str,)),
		'closed': (gobject.SIGNAL_RUN_LAST, None, ())
	}

	def __init__(self, bot, nickname, password, channels, send_as_notice = False, invisible = True):
		"""
			Constructor, calls parent constructors
		"""

		gobject.GObject.__init__(self)
		super(Client, self).__init__(nickname, password, invisible)
		self.bot = bot
		self.channels = channels
		self.send_as_notice = send_as_notice
		self.last_message = None

	def handle_write(self):
		if len(self.send_queue) != 0:
			item = self.send_queue[0]
			item.sent(self.connection.send(item.read()))

			if item.is_complete():
				del self.send_queue[0]
				string = str(item)
				del item

				self.emit('data-sent', string)

	def handle_close(self):
		print 'close'
		self.emit('closed')

	def on_line_received(self, data):
		super(Client, self).on_line_received(data)
		self.emit('data-received', data)

	def check_message(self, message):
		"""
			This methods inspects a received irc message. It checks if it contains a bot
			command, and if so, parses the command name, and arguments

			Then it passes the message through our plugin manager, and eventually respons to ping
			or joins the channels when the time is right.

			@type message: luckybot.luckynet.protocols.irc.ServerMessage
			@param message: The IRC Message
		"""
		data = str(message)
		self.last_message = message

		if message == None:
			return

		if isinstance(message, irc.ChannelMessage):
			cmd_prefix = self.bot.settings.get('Bot', 'command_prefix')

			# A message sent in PM/Channel
			if message.message[0:len(cmd_prefix)] == cmd_prefix:
				space_pos = message.message.find(' ', len(cmd_prefix))
				if space_pos == -1:
					space_pos = len(message.message)

				command = message.message[len(cmd_prefix):space_pos]
				message.bot_command = command
				message.bot_args = message.message[space_pos+1:]

		event = Event(message, self, self.bot)

		self.emit('irc-event', event)

		if isinstance(message, irc.ChannelMessage):
			if hasattr(self, 'on_message'):
				self.on_message(message)
		elif isinstance(message, irc.ServerMessage):
			if hasattr(self, 'on_command_%s' % message.command):
				func = getattr(self, 'on_command_%s' % message.command)
				func(message)

			if hasattr(self, 'on_command'):
				self.on_command(message)

	def on_command_001(self, event):
		"""
			Called when we succesfully authenticate with the IRC Server
			This means we can safely join
		"""

		for channel in self.channels:
			self.join(channel.strip())

	def send_pm(self, nick, message):
		"""
			Used to send privmsges to channels or nicknames
		"""

		if nick.startswith('#') and self.send_as_notice:
			self.send_notice(self.last_message.nick, message)
		else:
			super(Client, self).send_pm(nick, message)

